'''
Created on Aug 12, 2009

@author: Roni
'''
import unittest
import graph
import os
import cliques
import cliques.experiment_runner
from cliques.cliqueFinder import cliqueFinder

class CliqueSearchAbstractTest(unittest.TestCase):
    '''
    classdocs
    '''
        
    def simulate_run(self,test_graph, algorithms, comp_funcs, k, start_node):
        ''' Use the algorithms to search for a k-clique on the test graph 
        starting from start_node, and compare them with comp_funcs '''  
        print " -- Start Run -- "      
        for algo in algorithms:
            algo.setup(test_graph, k, start_node)
        try:
            base_alg = algorithms[0]
            while base_alg.halt() == False:
                for alg in algorithms:
                    print "Step %d alg=%s" % (alg.iteration,alg)
                    alg.step()
                
                for compared_algo in algorithms[1:]:
                    for comp_func in comp_funcs:
                        current_func = comp_func
                        current_func(base_alg, compared_algo)
        except AssertionError, error:
            self.backup_graph(test_graph, "BUG-GRAPH[%d,%s].graph" % (k, start_node))
            print "Assertion of %s Failed" % current_func
            raise error

    def exportImportGraph(self,exp_graph):
        current_graph_file = "TEMP-GRAPH.graph"
        graph_xml = exp_graph.write()
        if os.path.isfile(current_graph_file):
            os.remove(current_graph_file)
        graph_file = open(current_graph_file,"w+")
        graph_file.write(graph_xml)
        graph_file.close()
        
        graph_file = open(current_graph_file,"r+")
        read_xml = graph_file.read()
        graph_file.close()
        exp_graph = graph.graph()
        exp_graph.read(read_xml)
        return exp_graph


    def backup_graph(self,graph,current_graph_file):
        ''' Stores the graph as a backup '''
        graph_xml = graph.write()
        if os.path.isfile(current_graph_file):
            os.remove(current_graph_file)
        graph_file = open(current_graph_file,"w+")
        graph_file.write(graph_xml)
        graph_file.close()
        

    def clique_search_full_run_comparator(self,nodes,min_k,max_k,algorithms,comp_funcs):
        for edges in xrange(nodes*(min_k-1),min(nodes*(nodes-1)/2,nodes*(max_k+1)),nodes):#xrange(nodes+1,nodes*(nodes-1)/2,1):
            print "--- Generating graph[%d,%d] --- " % (nodes,edges)
            test_graph = graph.graph()
            test_graph.generate(nodes,edges)
            self.full_run_compare(test_graph,min_k,max_k,algorithms,comp_funcs)

    def full_run_compare(self,test_graph,min_k,max_k,algorithms,comp_funcs):  
        ''' Compare the run of the algorithms using the comp_functions,
        when searching for k-cliques in the given graph '''   
        clique_finder = cliqueFinder()
        for k in xrange(min_k,min(max_k,len(test_graph.nodes()))):    
            clique_finder.setup(test_graph)
            #print "-- Searching for a %d-clique in test graph..." % k
            clique = clique_finder.find_clique(k,test_graph.nodes())
            if clique is not None:
                clique = set(clique)
               
            start_node = cliques.experiment_runner.choose_start(test_graph)
            self.simulate_full_run(test_graph, algorithms, comp_funcs, k, start_node)
                 
    def simulate_full_run(self,test_graph, algorithms, comp_funcs, k, start_node):
        ''' Use the algorithms to search for a k-clique on the test graph 
        starting from start_node, and compare them with comp_funcs '''  
#        print " -- Start Run -- "      
        for algo in algorithms:
            print "Run alg %s" % algo
            algo.setup(test_graph, k, start_node)
            algo.run(test_graph,k,start_node)
        
        base_alg = algorithms[0]
        try:
            for compared_algo in algorithms[1:]:
                for comp_func in comp_funcs:
                    current_func = comp_func
                    current_func(base_alg, compared_algo)         
        except AssertionError, error:
            self.backup_graph(test_graph, "BUG-GRAPH[%d,%s].graph" % (k, start_node))
            print "Assertion of %s Failed" % current_func
            raise error
 

    def clique_search_run_comparator(self,nodes,min_k,max_k,algorithms,comp_funcs):
        for edges in xrange(nodes+1,nodes+2):#xrange(nodes+1,nodes*(nodes-1)/2,1):
            print "--- Generating graph[%d,%d] --- " % (nodes,edges)
            test_graph = graph.graph()
            test_graph.generate(nodes,edges)
            self.compare(test_graph,min_k,max_k,algorithms,comp_funcs)
            
    def compare(self,test_graph,min_k,max_k,algorithms,comp_funcs):  
        ''' Compare the run of the algorithms using the comp_functions,
        when searching for k-cliques in the given graph '''   
        clique_finder = cliqueFinder()
        for k in xrange(min_k,min(max_k,len(test_graph.nodes()))):    
            clique_finder.setup(test_graph)
            #print "-- Searching for a %d-clique in test graph..." % k
            clique = clique_finder.find_clique(k,test_graph.nodes())
            if clique is not None:
                clique = set(clique)
               
            start_node = cliques.experiment_runner.choose_start(test_graph)
            self.simulate_run(test_graph, algorithms, comp_funcs, k, start_node)
                 

    def assert_halt(self,alg1,alg2):
        assert alg1.halt()==alg2.halt()
        
    def assert_current_node(self,alg1,alg2):
        assert alg1.current_node==alg2.current_node        